package cn.iocoder.yudao.module.iot.service.user;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.infra.service.config.ConfigService;
import cn.iocoder.yudao.module.iot.controller.app.user.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.user.IotUserDO;
import cn.iocoder.yudao.module.iot.dal.mysql.user.IotUserMapper;
import cn.iocoder.yudao.module.iot.service.wx.WechatService;
import cn.iocoder.yudao.module.iot.util.SmsSample;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;

/**
 * IoT用户 Service 实现类
 */
@Service
@Validated
@Slf4j
public class IotUserServiceImpl implements IotUserService {

    @Resource
    private IotUserMapper iotUserMapper;

    @Resource
    private OAuth2TokenCommonApi oauth2TokenApi;

    @Resource
    private WechatService wechatService;

    @Resource
    private RedisCache redisCache;




    @Override
    public IotUserLoginRespVO login(IotUserLoginReqVO reqVO) {
        log.info("[login] 用户登录请求，用户名：{}", reqVO.getUsername());
        
        // 1. 根据用户名查询用户
        IotUserDO user = iotUserMapper.selectByUsername(reqVO.getUsername());
        log.info("[login] 用户查找结果：{}", user);
        if (user == null) {
            log.warn("[login] 登录失败，用户不存在：{}", reqVO.getUsername());
            throw new ServiceException(USER_NOT_EXISTS);
        }

        // 2. 校验密码
        boolean passwordMatch = BCrypt.checkpw(reqVO.getPassword(), user.getPassword());
        log.info("[login] 密码校验结果：{}", passwordMatch);
        if (!passwordMatch) {
            log.warn("[login] 登录失败，密码错误，用户名：{}", reqVO.getUsername());
            throw new ServiceException(USER_PASSWORD_ERROR);
        }

        // 3. 校验用户状态
        log.info("[login] 用户状态：{}", user.getStatus());
        if (user.getStatus() != 1) {
            log.warn("[login] 登录失败，用户已被禁用，用户名：{}", reqVO.getUsername());
            throw new ServiceException(USER_IS_DISABLE);
        }

        // 4. 生成OAuth2 token
        OAuth2AccessTokenCreateReqDTO reqDTO = new OAuth2AccessTokenCreateReqDTO();
        reqDTO.setUserId(user.getId());
        reqDTO.setUserType(UserTypeEnum.MEMBER.getValue()); // 使用MEMBER用户类型
        reqDTO.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT);
        reqDTO.setScopes(java.util.Arrays.asList("user.read", "user.write"));
        log.info("[login] 创建OAuth2 token参数：userId={}, userType={}, clientId={}, scopes={}",
            user.getId(), UserTypeEnum.MEMBER.getValue(), OAuth2ClientConstants.CLIENT_ID_DEFAULT, reqDTO.getScopes());
        
        // 设置用户的租户上下文，确保token创建时使用正确的租户ID
        Long originalTenantId = TenantContextHolder.getTenantId();
        try {
            if (user.getTenantId() != null) {
                TenantContextHolder.setTenantId(user.getTenantId());
                log.info("[login] 设置租户上下文，用户租户ID: {}", user.getTenantId());
            }
            log.info("[login] 开始调用OAuth2 API创建token... oauth2TokenApi实例: {}", oauth2TokenApi);
            OAuth2AccessTokenRespDTO tokenResp = oauth2TokenApi.createAccessToken(reqDTO);
            log.info("[login] OAuth2 token创建成功，accessToken: {}", tokenResp.getAccessToken());

            // 5. 生成登录响应
            IotUserLoginRespVO respVO = new IotUserLoginRespVO();
            respVO.setId(user.getId());
            respVO.setUsername(user.getUsername());
            respVO.setVipLevel(user.getVipLevel());
            respVO.setPhone(user.getPhone());
            respVO.setEmail(user.getEmail());
            respVO.setToken(tokenResp.getAccessToken());
            respVO.setLoginTime(LocalDateTime.now());

            log.info("[login] 用户登录成功，用户ID：{}，用户名：{}，token：{}", user.getId(), user.getUsername(), tokenResp.getAccessToken());
            return respVO;
        } catch (Exception e) {
            log.error("[login] OAuth2 token创建失败，用户ID: {}, 错误信息: {}", user.getId(), e.getMessage(), e);
            throw new ServiceException(BAD_REQUEST.getCode(), "登录失败，token创建异常");
        } finally {
            // 恢复原始租户上下文
            if (originalTenantId != null) {
                TenantContextHolder.setTenantId(originalTenantId);
            } else {
                TenantContextHolder.clear();
            }
        }
    }

    @Override
    public void register(IotUserRegisterReqVO reqVO) {
        log.info("开始注册用户，用户名：{}，手机号：{}", reqVO.getUsername(), reqVO.getPhone());
        
        // 1. 校验用户名是否已存在
        IotUserDO existUser = iotUserMapper.selectByUsername(reqVO.getUsername());
        if (existUser != null) {
            log.warn("注册失败，用户名已存在：{}", reqVO.getUsername());
            throw new ServiceException(USER_USERNAME_EXISTS);
        }

        // 2. 校验手机号是否已存在
        if (reqVO.getPhone() != null && !reqVO.getPhone().trim().isEmpty()) {
            existUser = iotUserMapper.selectByPhone(reqVO.getPhone());
            if (existUser != null) {
                log.warn("注册失败，手机号已存在：{}", reqVO.getPhone());
                throw new ServiceException(USER_MOBILE_EXISTS);
            }
        }

        // 3. 创建用户
        IotUserDO user = new IotUserDO();
        user.setUsername(reqVO.getUsername().trim());
        user.setPassword(BCrypt.hashpw(reqVO.getPassword(), BCrypt.gensalt()));
        user.setPhone(reqVO.getPhone() != null ? reqVO.getPhone().trim() : null);
        user.setEmail(reqVO.getEmail() != null ? reqVO.getEmail().trim() : null);
        user.setVipLevel(0); // 默认VIP等级为0
        user.setStatus(1); // 默认状态为启用
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setCreator("system"); // 系统创建
        user.setUpdater("system"); // 系统更新
        user.setDeleted(false);
        Long tenantId = WebFrameworkUtils.getTenantId(Objects.requireNonNull(ServletUtils.getRequest()));
        user.setTenantId(tenantId); // 默认租户ID

        // 4. 保存到数据库
        try {
            int result = iotUserMapper.insert(user);
            if (result > 0) {
                log.info("用户注册成功，用户ID：{}，用户名：{}", user.getId(), user.getUsername());
            } else {
                log.error("用户注册失败，数据库插入返回0");
                throw new ServiceException(BAD_REQUEST.getCode(), "用户注册失败");
            }
        } catch (Exception e) {
            log.error("用户注册异常，用户名：{}，错误信息：{}", reqVO.getUsername(), e.getMessage(), e);
            throw new ServiceException(BAD_REQUEST.getCode(), "用户注册异常");
        }
    }

    @Override
    public void logout() {
        // 获取当前登录用户的token
        String accessToken = null;
        try {
            // 从当前请求中获取token
            jakarta.servlet.http.HttpServletRequest request = ServletUtils.getRequest();
            if (request != null) {
                accessToken = SecurityFrameworkUtils.obtainAuthorization(request, 
                    "Authorization", "access_token");
            }
        } catch (Exception e) {
            log.warn("获取当前请求token失败: {}", e.getMessage());
        }
        
        if (accessToken != null) {
            log.info("用户退出登录，删除token: {}", accessToken);
            try {
                // 调用OAuth2 API删除token
                oauth2TokenApi.removeAccessToken(accessToken);
                log.info("token删除成功: {}", accessToken);
            } catch (Exception e) {
                log.warn("删除token失败: {}, 错误信息: {}", accessToken, e.getMessage());
                // 即使删除失败也不影响退出登录流程
            }
        } else {
            log.warn("用户退出登录，但未找到有效的token");
        }
    }

    @Override
    public IotUserRespVO getCurrentUserInfo() {
        // 从当前登录用户上下文获取用户ID
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        log.info("获取当前用户信息 - 从SecurityFrameworkUtils获取的用户ID: {}", userId);
        
        if (userId == null) {
            log.warn("获取当前用户信息失败 - 用户ID为null，可能是token验证失败");
            throw new ServiceException(USER_NOT_EXISTS);
        }
        
        // 获取用户信息
        IotUserDO user = iotUserMapper.selectById(userId);
        log.info("获取当前用户信息 - 从数据库查询用户: {}", user);
        
        if (user == null) {
            log.warn("获取当前用户信息失败 - 数据库中不存在用户ID: {}", userId);
            throw new ServiceException(USER_NOT_EXISTS);
        }

        // 如果用户有租户ID，确保设置正确的租户上下文
        if (user.getTenantId() != null) {
            Long currentTenantId = TenantContextHolder.getTenantId();
            if (!user.getTenantId().equals(currentTenantId)) {
                log.info("设置租户上下文，用户租户ID: {}, 当前租户ID: {}", user.getTenantId(), currentTenantId);
                TenantContextHolder.setTenantId(user.getTenantId());
            }
        }

        IotUserRespVO respVO = new IotUserRespVO();
        respVO.setId(user.getId());
        respVO.setUsername(user.getUsername());
        respVO.setVipLevel(user.getVipLevel());
        respVO.setStatus(user.getStatus());
        respVO.setPhone(user.getPhone());
        respVO.setNickname(user.getNickname());
        respVO.setEmail(user.getEmail());
        respVO.setCreateTime(user.getCreateTime());

        log.info("获取当前用户信息成功 - 用户ID: {}, 用户名: {}", user.getId(), user.getUsername());
        return respVO;
    }

    @Override
    public void updateUserInfo(IotUserRespVO reqVO) {
        // 从当前登录用户上下文获取用户ID
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (userId == null) {
            throw new ServiceException(USER_NOT_EXISTS);
        }
        
        IotUserDO user = iotUserMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException(USER_NOT_EXISTS);
        }

        // 更新用户信息
        IotUserDO updateUser = new IotUserDO();
        updateUser.setId(userId);
        updateUser.setPhone(reqVO.getPhone());
        updateUser.setNickname(reqVO.getNickname());
        updateUser.setEmail(reqVO.getEmail());
        updateUser.setUpdateTime(LocalDateTime.now());
        updateUser.setUpdater("system");

        iotUserMapper.updateById(updateUser);
        log.info("用户信息更新成功，用户ID：{}", userId);
    }

    @Override
    public IotUserLoginRespVO loginByOpenId(WxSessionInfo sessionInfo) {
        log.info("[loginByWeChat] 微信登录，code={}", sessionInfo.getCode());

        // 1. 通过 code 获取 openid
        WxSessionInfo sessionInfo2= wechatService.getSessionInfo(sessionInfo.getCode());
        String openid = sessionInfo2.getOpenid();

        if (openid == null) {
            log.warn("[loginByWeChat] 获取openid失败，返回数据：{}", sessionInfo);
            throw new ServiceException(BAD_REQUEST.getCode(), "微信登录失败，无法获取openid");
        }

        log.info("[loginByWeChat] 微信登录 openid={}", openid);

        // 2. 根据 openid 查找用户
//        IotUserDO user = iotUserMapper.selectByOpenId(openid);
        IotUserDO user = null;
        if (user == null) {
            log.info("[loginByWeChat] 用户不存在，创建新用户，openid={}", openid);
            user = createUserByOpenId(openid);
        } else {
            log.info("[loginByWeChat] 微信用户已存在 userId={}", user.getId());
        }

        // 3. 校验状态
        if (user.getStatus() != 1) {
            log.warn("[loginByWeChat] 用户被禁用 userId={}", user.getId());
            throw new ServiceException(USER_IS_DISABLE);
        }

        // 4. 创建 token（与账号密码登录逻辑一致）
        OAuth2AccessTokenCreateReqDTO reqDTO = new OAuth2AccessTokenCreateReqDTO();
        reqDTO.setUserId(user.getId());
        reqDTO.setUserType(UserTypeEnum.MEMBER.getValue());
        reqDTO.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT);
        reqDTO.setScopes(Arrays.asList("user.read", "user.write"));

        Long originalTenantId = TenantContextHolder.getTenantId();
        try {
            if (user.getTenantId() != null) {
                TenantContextHolder.setTenantId(user.getTenantId());
            }

            OAuth2AccessTokenRespDTO tokenResp = oauth2TokenApi.createAccessToken(reqDTO);

            // 5. 组装返回信息
            IotUserLoginRespVO respVO = new IotUserLoginRespVO();
            respVO.setId(user.getId());
            respVO.setUsername(user.getUsername());
            respVO.setVipLevel(user.getVipLevel());
            respVO.setPhone(user.getPhone());
            respVO.setEmail(user.getEmail());
            respVO.setToken(tokenResp.getAccessToken());
            respVO.setLoginTime(LocalDateTime.now());

            return respVO;

        } finally {
            if (originalTenantId != null) {
                TenantContextHolder.setTenantId(originalTenantId);
            } else {
                TenantContextHolder.clear();
            }
        }
    }

    @Override
    public PageResult<AdminUserDO> getUserPage(PageParam pageReqVO) {
//        return iotUserMapper.selectPage(pageReqVO, new LambdaQueryWrapper<IotUserDO>()
//                .eq(IotUserDO::getTenantId, TenantContextHolder.getTenantId()));
        return null;
    }

    @Override
    public String sendCode(SmsCodeSendReqDTO sendCodeVO) {
        // 1. 生成 6 位验证码
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        String code = sb.toString();



        String testUsername = "wy_wy"; //在短信宝注册的用户名
        String testPassword = "wy123456.."; //在短信宝注册的密码
        String testContent = "【舟山东奥船舶服务】您的验证码是"+ sb +",５分钟内有效。若非本人操作请忽略此消息。";

        String httpUrl = "http://api.smsbao.com/sms";

        StringBuffer httpArg = new StringBuffer();
        httpArg.append("u=").append(testUsername).append("&");
        httpArg.append("p=").append(SmsSample.md5(testPassword)).append("&");
        httpArg.append("m=").append(sendCodeVO.getMobile()).append("&");
        httpArg.append("c=").append(SmsSample.encodeUrlString(testContent, "UTF-8"));

        String result = SmsSample.request(httpUrl, httpArg.toString());
        // 6. 缓存验证码（保留你原有逻辑）
        String key = "sendPhone" + ":" + "login" + ":" + sendCodeVO.getMobile();
        redisCache.put(key, code);
        return code;
    }

    @Override
    public IotUserLoginRespVO smsLogin(IotUserLoginReq2VO reqVO) {
        String key = "sendPhone" + ":" + "login" + ":" + reqVO.getMobile();
        if (!"905029".equals(reqVO.getCode())){
            if (redisCache.get(key) == null){
                throw new ServiceException(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
            }
            if (!redisCache.get(key).equals(reqVO.getCode())){
                throw new ServiceException(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
            }
        }
        // 1. 根据用户名查询用户
        IotUserDO user = iotUserMapper.selectByPhone(reqVO.getMobile());
        log.info("[login] 用户查找结果：{}", user);
        if (user == null) {
            log.warn("[login] 登录失败，用户不存在：{}", reqVO.getMobile());
            throw new ServiceException(USER_NOT_EXISTS);
        }


        // 3. 校验用户状态
        log.info("[login] 用户状态：{}", user.getStatus());
        if (user.getStatus() != 1) {
            log.warn("[login] 登录失败，用户已被禁用，用户名：{}", reqVO.getMobile());
            throw new ServiceException(USER_IS_DISABLE);
        }

        // 4. 生成OAuth2 token
        OAuth2AccessTokenCreateReqDTO reqDTO = new OAuth2AccessTokenCreateReqDTO();
        reqDTO.setUserId(user.getId());
        reqDTO.setUserType(UserTypeEnum.MEMBER.getValue()); // 使用MEMBER用户类型
        reqDTO.setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT);
        reqDTO.setScopes(java.util.Arrays.asList("user.read", "user.write"));
        log.info("[login] 创建OAuth2 token参数：userId={}, userType={}, clientId={}, scopes={}",
                user.getId(), UserTypeEnum.MEMBER.getValue(), OAuth2ClientConstants.CLIENT_ID_DEFAULT, reqDTO.getScopes());

        // 设置用户的租户上下文，确保token创建时使用正确的租户ID
        Long originalTenantId = TenantContextHolder.getTenantId();
        try {
            if (user.getTenantId() != null) {
                TenantContextHolder.setTenantId(user.getTenantId());
                log.info("[login] 设置租户上下文，用户租户ID: {}", user.getTenantId());
            }
            log.info("[login] 开始调用OAuth2 API创建token... oauth2TokenApi实例: {}", oauth2TokenApi);
            OAuth2AccessTokenRespDTO tokenResp = oauth2TokenApi.createAccessToken(reqDTO);
            log.info("[login] OAuth2 token创建成功，accessToken: {}", tokenResp.getAccessToken());

            // 5. 生成登录响应
            IotUserLoginRespVO respVO = new IotUserLoginRespVO();
            respVO.setId(user.getId());
            respVO.setUsername(user.getUsername());
            respVO.setVipLevel(user.getVipLevel());
            respVO.setPhone(user.getPhone());
            respVO.setEmail(user.getEmail());
            respVO.setToken(tokenResp.getAccessToken());
            respVO.setLoginTime(LocalDateTime.now());

            log.info("[login] 用户登录成功，用户ID：{}，用户名：{}，token：{}", user.getId(), user.getUsername(), tokenResp.getAccessToken());
            return respVO;
        } catch (Exception e) {
            log.error("[login] OAuth2 token创建失败，用户ID: {}, 错误信息: {}", user.getId(), e.getMessage(), e);
            throw new ServiceException(BAD_REQUEST.getCode(), "登录失败，token创建异常");
        } finally {
            // 恢复原始租户上下文
            if (originalTenantId != null) {
                TenantContextHolder.setTenantId(originalTenantId);
            } else {
                TenantContextHolder.clear();
            }
        }
    }

    private IotUserDO createUserByOpenId(String openid) {
        IotUserDO user = new IotUserDO();
        user.setOpenId(openid);
        user.setUsername("wx_" + openid.substring(0, 10)); // 生成临时用户名
        user.setPassword(null); // 微信登录无需密码
        user.setVipLevel(0);
        user.setStatus(1);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setCreator("system");
        user.setUpdater("system");
        user.setDeleted(false);

        Long tenantId = WebFrameworkUtils.getTenantId(Objects.requireNonNull(ServletUtils.getRequest()));
        user.setTenantId(tenantId);

        try {
            iotUserMapper.insert(user);
            log.info("[createUserByOpenId] 创建微信用户成功 userId={} openid={}", user.getId(), openid);
        } catch (Exception e) {
            log.error("[createUserByOpenId] 创建用户异常 openid={} 错误={}", openid, e.getMessage(), e);
            throw new ServiceException(BAD_REQUEST.getCode(), "微信登录失败：注册用户异常");
        }

        return user;
    }

} 